package com.appspot.gaeforum309.web;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


import com.appspot.gaeforum309.db.DBCategory;
import com.appspot.gaeforum309.db.DBComment;
import com.appspot.gaeforum309.db.DBConversation;
import com.appspot.gaeforum309.db.DBTopic;
import com.appspot.gaeforum309.pathing.Path;
import com.appspot.gaeforum309.pathing.PathRoot;
import com.appspot.gaeforum309.pathing.PathBuilder.IPathable;

import javax.servlet.http.*;

// TODO: Write a template "TemplateJSP" which permit to construct template with jsp pages.
// TODO: Make possible to customize templates with a configuration. 
//	     Each template will define list of properties (can be color, text, integer, boolean, ...).
//       A page permit to create themes. A theme will be a template with a special configuration. A same template can be used on
//       many themes.
// TODO: For version 0.1, we conserve this template system. But it is not usefull, we trash it after !!!!
public abstract class Template {

	public interface ITemplateSection
	{
		void head(StringBuilder response, Path path, IPathable object);
		void body(StringBuilder response, Path path, IPathable object);
		void foot(StringBuilder response, Path path, IPathable object);
	}
	
	private Map<String, ITemplateSection> sections = new HashMap<String, ITemplateSection>();
	
	protected void addSection(String tagName, ITemplateSection section)
	{
		sections.put(tagName, section);
	}
	
	/**
	 * Initialize the template.
	 * @param page Page which create the template.
	 */
	public abstract void initTemplate(ForumPages.PageInfo pageInfo);
	
	/**
	 * Return the content type of generated page by template.
	 * @return
	 */
	public abstract String contentType();

	// TODO: Send path AND object of the type of the section(DBComment for begin/endComment, ...).
	// This is an optimization !
	
	/**
	 * Implement it to generate the header of all pages of the forum
	 * @param response Content writed in this buffer will be directly sent to the client at the begining of the page. 
	 * @param currentPage Indicate the current page of the forum.
	 */
	public abstract void beginPage(StringBuilder response, Path path);
	
	/**
	 * Implement it to generate the footer of all pages if the forum
	 * @param response Content writed in this buffer will be directly sent to client at the end of the page. 
	 * @param currentPage Indicate the current page of the forum.
	 */
	public abstract void endPage(StringBuilder response, Path path);
	
	/*
	public abstract void beginCategorie(StringBuilder response, Path path, DBCategory category);
	public abstract void writeCategorie(StringBuilder response, Path path, DBCategory category);
	public abstract void endCategorie(StringBuilder response, Path path, DBCategory category);
	
	public abstract void beginTopic(StringBuilder response, Path path, DBTopic topic);
	public abstract void writeTopic(StringBuilder response, Path path, DBTopic topic);
	public abstract void endTopic(StringBuilder response, Path path, DBTopic topic);
	
	public abstract void beginConversation(StringBuilder response, Path path, DBConversation conversation);
	public abstract void writeConversation(StringBuilder response, Path path, DBConversation conversation);
	public abstract void endConversation(StringBuilder response, Path path, DBConversation conversation);
	
	public abstract void beginComment(StringBuilder response, Path path, DBComment comment);
	public abstract void writeComment(StringBuilder response, Path path, DBComment comment);
	public abstract void endComment(StringBuilder response, Path path, DBComment comment);
	*/
	
	private boolean headSection(StringBuilder response, Path path, IPathable object)
	{
		if(PathRoot.tagName.equals(object.getPathable().getTagName()))
			return true;
		
		ITemplateSection its = sections.get(object.getPathable().getTagName());
		if(its == null)
			return false; // Object not supported by this template.
		
		its.head(response, path, object);
		return true;
	}
	
	private boolean bodySection(StringBuilder response, Path path, IPathable object)
	{
		if(PathRoot.tagName.equals(object.getPathable().getTagName()))
			return true;
		
		ITemplateSection its = sections.get(object.getPathable().getTagName());
		if(its == null)
			return false; // Object not supported by this template.
		
		its.body(response, path, object);
		return true;
	}
	
	private boolean footSection(StringBuilder response, Path path, IPathable object)
	{
		if(PathRoot.tagName.equals(object.getPathable().getTagName()))
			return true;
		
		ITemplateSection its = sections.get(object.getPathable().getTagName());
		if(its == null)
			return false; // Object not supported by this template.
		
		its.foot(response, path, object);
		return true;
	}
	
	private boolean generatePageSection(StringBuilder buildContent, Path path, IPathable object, String tagShowLevel)
	{
		if(object.getPathable().getTagName().equals(tagShowLevel))
		{
			return bodySection(buildContent, path, object);
		}
		
		if(!headSection(buildContent, path, object))
			return false;
		
		for(IPathable child:object.getChilds())
		{
			if(!generatePageSection(buildContent, path, child, tagShowLevel))
				return false;
		}
		
		if(!footSection(buildContent, path, object))
			return false;
		
		return true;
	}
	
	public void generatePage(HttpServletRequest req, HttpServletResponse resp, Path path) throws IOException
	{
		StringBuilder buildContent = new StringBuilder();
		
		String tagShowLevel = null;
		String pathTagName = path.objectTagName();
		
		if(DBCategory.tagName.equals(pathTagName) || PathRoot.tagName.equals(pathTagName))
		{
			tagShowLevel = DBTopic.tagName;
		}
		
		if(DBTopic.tagName.equals(pathTagName))
		{
			tagShowLevel = DBConversation.tagName;
		}
		
		if(DBConversation.tagName.equals(pathTagName))
		{
			tagShowLevel = DBComment.tagName;
		}
		
		if(DBComment.tagName.equals(pathTagName))
		{
			tagShowLevel = DBComment.tagName;
		}
		
		if(tagShowLevel == null)
		{
			// TODO: Catch this problem
			
			return;
		}
		
		IPathable ip = path.object();
		
		beginPage(buildContent, path);
		
		if(!generatePageSection(buildContent, path, ip, tagShowLevel))
		{
			resp.getWriter().write("<html><body><H1>Template fail to render the page, probably due to an unsupported tagName.</H1></body></html>");
			return;
		}
		
		endPage(buildContent, path);
		
		resp.getWriter().write(buildContent.toString());
	}
}
